package icu.mohan.erp.call.util;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Map;
import java.util.TreeMap;

/**
 * 请求签名工具类
 *
 * @author yanglihao
 */
public class SignatureUtil {

    /**
     * 生成签名字符串
     * 
     * @param appSecret 平台appSecret
     * @param timestamp 请求时间戳
     * @param bodyParams 请求体
     * @return 签名字符串
     */
    public static String generateSignature(String appSecret, long timestamp, Map<String, String> bodyParams)
        throws Exception {

        // 步骤1：将请求报文中的body参数和请求头中的timestamp组成【有序键值对列表】
        Map<String, String> allParams = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);// 使用TreeMap保证排序
        allParams.putAll(bodyParams);
        allParams.put("timestamp", String.valueOf(timestamp));

        // 步骤2：将列表中的参数对按URL键值对的格式拼接成字符串T
        StringBuilder stringT = new StringBuilder();
        for (Map.Entry<String, String> entry : allParams.entrySet()) {
            if (stringT.length() > 0) {
                stringT.append("&");
            }
            stringT.append(entry.getKey()).append("=").append(urlEncode(entry.getValue()));
        }

        // 步骤3：将应用密钥以key为键名，组成URL键值拼接到字符串T末尾
        String stringS = stringT.append("&key=").append(appSecret).toString();

        // 步骤4：对字符串S进行MD5运算，并返回大写形式的哈希值作为签名
        return md5(stringS);
    }

    // 将字符串进行URL编码
    private static String urlEncode(String value) throws UnsupportedEncodingException {
        return URLEncoder.encode(value, "UTF-8");
    }

    // 对字符串进行MD5运算，并返回大写形式的哈希值
    private static String md5(String input) throws NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] messageDigest = md.digest(input.getBytes());
        StringBuilder hexString = new StringBuilder();
        for (byte b : messageDigest) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString().toUpperCase();
    }
}
